﻿<template>
    <div class="flow-designer">
        <!-- 左侧工序面板 -->
        <div class="process-panel fixed-panel" :style="{ width: panelWidth + 'px' }">
            <div class="resize-handle" @mousedown="startPanelResize"></div>
            <div class="panel-header">
                <!-- 搜索框 -->
                <input
                    type="text"
                    placeholder="请输入工序名称"
                    v-model="searchQuery"
                    class="search-input"
                />
                <!-- 折叠按钮 -->
                <button type="button" @click="toggleCollapse" class="collapse-button">
                    <i :class="collapsed ? 'fa-solid fa-plus' : 'fa-solid fa-minus'"></i>
                </button>
            </div>

            <!-- 可拖拽工序列表 -->
            <div class="process-list" v-if="!collapsed">
                <div
                    v-for="item in filteredProcessList"
                    :key="item.id"
                    class="process-item"
                    draggable="true"
                    @dragstart="handleDragStart($event, item)"
                    @dragend="handleDragEnd"
                >
                    <div class="process-icon" :style="{ background: item.color }"></div>
                    <span>{{ item.name }}</span>
                    <span class="process-code">{{ item.code }}</span>
                </div>
            </div>
        </div>

        <!-- 流程图区域 -->
        <div class="flow-canvas fullscreen-canvas" @dragover.prevent="handleDragOver" @drop="handleDrop">
            <svg :width="canvasWidth" :height="canvasHeight" ref="svgCanvas">
                <!-- 网格背景 -->
                <pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
                    <path d="M 40 0 L 0 0 0 40" fill="none" stroke="#e0e0e0" stroke-width="1" />
                </pattern>
                <rect width="100%" height="100%" fill="url(#grid)" />

                <!-- 流程节点 -->
                <g v-for="node in nodes" :key="node.id" :transform="`translate(${node.x},${node.y})`" @mousedown="startNodeDrag(node, $event)">
                    <rect width="120" height="60" rx="4" :fill="node.type === 'start' ? '#52c41a' : '#1890ff'" stroke="#fff" stroke-width="2" />
                    <text x="60" y="30" text-anchor="middle" fill="#fff" font-size="14">
                        {{ node.label }}
                        <tspan x="60" dy="20" font-size="12">{{ node.subLabel }}</tspan>
                    </text>
                    <!-- 连接锚点 -->
                    <circle class="anchor output" cx="120" cy="30" r="4" fill="#fff" @mousedown.stop="startLinking(node, $event)" />
                    <circle class="anchor input" cx="0" cy="30" r="4" fill="#fff" />
                    <!-- 删除按钮 -->
                    <circle cx="110" cy="10" r="8" fill="#ff4d4f" @click.stop="deleteNode(node.id)" />
                    <text x="110" y="14" text-anchor="middle" fill="#fff" font-size="10">X</text>
                </g>
                <!-- 连接线 -->
                <g v-for="(link, index) in links" :key="index">
                    <path :d="calculateLinkPath(link)" stroke="#666" fill="none" marker-end="url(#arrowhead)" />
                </g>
                <!-- 临时连线 -->
                <path v-if="tempLink" :d="tempLinkPath" stroke="#666" stroke-dasharray="4" marker-end="url(#arrowhead)" />
                <!-- 箭头标记 -->
                <marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
                    <polygon points="0 0, 10 3.5, 0 7" fill="#666" />
                </marker>
            </svg>
        </div>
        <!-- 保存按钮 -->
        <button class="save-button" @click="saveFlowchart">
            <i class="fa-solid fa-save"></i> 保存流程图
        </button>
    </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, defineEmits, toRefs } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';
import { usetechnologicalprocessApi } from '/@/api/technology/technologicalprocess';

const route = useRoute();
const router = useRouter();
const name = route.query.id;
const technologicalprocessApi = usetechnologicalprocessApi();

// 工序数据
const processList = reactive([
    {
        id: 'start',
        type: 'start',
        name: '开始',
        code: 'START',
        color: '#52c41a',
        width: 120,
        height: 60,
    },
    {
        id: 'material_preparation',
        type: 'process',
        name: '原材料准备',
        code: 'MP01',
        color: '#1890ff',
        width: 120,
        height: 60,
    },
    {
        id: 'plastic_inspection',
        type: 'process',
        name: '塑料原材料检验',
        code: 'PI01',
        color: '#fadb14',
        width: 120,
        height: 60,
    },
    {
        id: 'copper_inspection',
        type: 'process',
        name: '铜材原材料检验',
        code: 'CI01',
        color: '#f00b14',
        width: 120,
        height: 60,
    },
    {
        id: 'plastic_molding',
        type: 'process',
        name: '塑料外壳成型',
        code: 'PM01',
        color: '#fadb14',
        width: 120,
        height: 60,
    },
    {
        id: 'plastic_finishing',
        type: 'process',
        name: '塑料外壳后处理',
        code: 'PF01',
        color: '#fa8c16',
        width: 120,
        height: 60,
    },
    {
        id: 'copper_terminal_processing',
        type: 'process',
        name: '铜端子加工',
        code: 'CTP01',
        color: '#f00b14',
        width: 120,
        height: 60,
    },
    {
        id: 'terminal_plating',
        type: 'process',
        name: '铜端子电镀',
        code: 'TP01',
        color: '#722ed1',
        width: 120,
        height: 60,
    },
    {
        id: 'circuit_design',
        type: 'process',
        name: '电路设计与布局',
        code: 'CD01',
        color: '#2f54eb',
        width: 120,
        height: 60,
    },
    {
        id: 'circuit_assembly',
        type: 'process',
        name: '电路组装',
        code: 'CA01',
        color: '#722ed1',
        width: 120,
        height: 60,
    },
    {
        id: 'inner_cover_assembly',
        type: 'process',
        name: '内盖组装',
        code: 'ICA01',
        color: '#fa8c16',
        width: 120,
        height: 60,
    },
    {
        id: 'outer_cover_assembly',
        type: 'process',
        name: '外盖组装',
        code: 'OCA01',
        color: '#2f54eb',
        width: 120,
        height: 60,
    },
    {
        id: 'pre_testing',
        type: 'process',
        name: '预测试',
        code: 'PT01',
        color: '#eb2f96',
        width: 120,
        height: 60,
    },
    {
        id: 'adjustment',
        type: 'process',
        name: '性能调整',
        code: 'ADJ01',
        color: '#52c41a',
        width: 120,
        height: 60,
    },
    {
        id: 'final_testing',
        type: 'process',
        name: '最终性能测试',
        code: 'FT01',
        color: '#eb2f96',
        width: 120,
        height: 60,
    },
    {
        id: 'labeling',
        type: 'process',
        name: '贴标签',
        code: 'LAB01',
        color: '#fadb14',
        width: 120,
        height: 60,
    },
    {
        id: 'packaging',
        type: 'process',
        name: '包装',
        code: 'P02',
        color: '#52c41a',
        width: 120,
        height: 60,
    },
    {
        id: 'storage',
        type: 'process',
        name: '入库存储',
        code: 'ST01',
        color: '#1890ff',
        width: 120,
        height: 60,
    },
    {
        id: 'end',
        type: 'end',
        name: '结束',
        code: 'END',
        color: '#52c41a',
        width: 120,
        height: 60,
    },
]);

// 父级传递来的函数，用于回调
const emit = defineEmits(['reloadTable']);

// 画布数据
const canvasWidth = ref(window.innerWidth);
const canvasHeight = ref(window.innerHeight);
const nodes = ref([]);

// 连接线数据
const links = ref([]);
let linkingStartNode = null;
const tempLink = ref(null);

// 拖拽逻辑
let draggingItem = null;

const handleDragStart = (e, item) => {
    draggingItem = item;
    e.dataTransfer.setData(
        'text/plain',
        JSON.stringify({
            type: item.type,
            width: item.width,
            height: item.height,
        })
    );
};

const handleDragOver = (e) => {
    // 显示拖拽位置预览
    const svg = e.target.closest('svg');
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    const { x, y } = pt.matrixTransform(svg.getScreenCTM().inverse());

    // 更新预览位置（可添加预览图形）
};

const handleDrop = (e) => {
    if (!draggingItem) return;

    const svg = e.target.closest('svg');
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    const { x, y } = pt.matrixTransform(svg.getScreenCTM().inverse());

    nodes.value.push({
        id: `${draggingItem.id}_${Date.now()}`,
        type: draggingItem.type,
        label: draggingItem.name,
        subLabel: draggingItem.code,
        x: x - draggingItem.width / 2,
        y: y - draggingItem.height / 2,
        width: draggingItem.width,
        height: draggingItem.height,
    });

    draggingItem = null;
};

const handleDragEnd = () => {
    draggingItem = null;
};

// 计算临时连线路径
const tempLinkPath = computed(() => {
    if (!tempLink.value) return '';
    const start = tempLink.value.start;
    const end = tempLink.value.end;
    return `M ${start.x} ${start.y} L ${end.x} ${end.y}`;
});

// 节点拖拽逻辑
const startNodeDrag = (node, e) => {
    const svg = e.target.closest('svg');
    // 获取初始坐标（转换为SVG坐标系）
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    const startPos = pt.matrixTransform(svg.getScreenCTM().inverse());
    // 记录初始位置
    const initialX = node.x;
    const initialY = node.y;
    // 添加临时样式防止选中
    document.body.style.userSelect = 'none';
    document.body.style.cursor = 'grabbing';
    const onMouseMove = (e) => {
        // 计算当前坐标（转换为SVG坐标系）
        pt.x = e.clientX;
        pt.y = e.clientY;
        const currentPos = pt.matrixTransform(svg.getScreenCTM().inverse());

        // 计算偏移量
        const deltaX = currentPos.x - startPos.x;
        const deltaY = currentPos.y - startPos.y;

        // 更新节点位置（使用新对象触发响应式更新）
        node.x = initialX + deltaX;
        node.y = initialY + deltaY;
    };

    const onMouseUp = () => {
        // 清理操作
        document.removeEventListener('mousemove', onMouseMove);
        document.removeEventListener('mouseup', onMouseUp);
        document.body.style.userSelect = '';
        document.body.style.cursor = '';
    };

    // 绑定到document保证移出画布也能跟踪
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);

    e.preventDefault();
};

// 连线逻辑
const startLinking = (node, e) => {
    const svg = e.target.closest('svg');
    const pt = svg.createSVGPoint();
    pt.x = e.clientX;
    pt.y = e.clientY;
    const startPos = pt.matrixTransform(svg.getScreenCTM().inverse());

    linkingStartNode = node;
    tempLink.value = { start: startPos, end: startPos };

    const onMouseMove = (e) => {
        pt.x = e.clientX;
        pt.y = e.clientY;
        const currentPos = pt.matrixTransform(svg.getScreenCTM().inverse());
        tempLink.value.end = currentPos;
    };

    const onMouseUp = (e) => {
        const target = document.elementsFromPoint(e.clientX, e.clientY).find((el) => el.classList.contains('anchor'));

        if (target?.classList.contains('input')) {
            const targetNode = nodes.value.find(
                (n) =>
                    n.x === parseFloat(target.parentNode.getAttribute('transform').split('(')[1].split(',')[0]) && n.y === parseFloat(target.parentNode.getAttribute('transform').split(',')[1].split(')')[0])
            );

            if (targetNode && targetNode !== linkingStartNode) {
                links.value.push({
                    source: linkingStartNode.id,
                    target: targetNode.id,
                });
            }
        }

        tempLink.value = null;
        svg.removeEventListener('mousemove', onMouseMove);
        svg.removeEventListener('mouseup', onMouseUp);
    };

    svg.addEventListener('mousemove', onMouseMove);
    svg.addEventListener('mouseup', onMouseUp);
    e.stopPropagation();
};

// 计算连接线路径
const calculateLinkPath = (link) => {
    const sourceNode = nodes.value.find((n) => n.id === link.source);
    const targetNode = nodes.value.find((n) => n.id === link.target);

    if (!sourceNode || !targetNode) return '';

    const start = {
        x: sourceNode.x + 120, // 右侧中间
        y: sourceNode.y + 30,
    };
    const end = {
        x: targetNode.x, // 左侧中间
        y: targetNode.y + 30,
    };

    // 贝塞尔曲线控制点
    const cp1 = { x: start.x + 50, y: start.y };
    const cp2 = { x: end.x - 50, y: end.y };

    return `M ${start.x} ${start.y} C ${cp1.x} ${cp1.y}, ${cp2.x} ${cp2.y}, ${end.x} ${end.y}`;
};

// 菜单调整大小逻辑
const panelWidth = ref(240);
let isResizingPanel = false;
let panelInitialX = 0;
let panelInitialWidth = 0;

const startPanelResize = (e) => {
    isResizingPanel = true;
    panelInitialX = e.clientX;
    panelInitialWidth = panelWidth.value;
    document.addEventListener('mousemove', panelResize);
    document.addEventListener('mouseup', endPanelResize);
    e.preventDefault();
};

const panelResize = (e) => {
    if (isResizingPanel) {
        const dx = e.clientX - panelInitialX;
        panelWidth.value = panelInitialWidth + dx;
    }
};

const endPanelResize = () => {
    isResizingPanel = false;
    document.removeEventListener('mousemove', panelResize);
    document.removeEventListener('mouseup', endPanelResize);
};

// 删除节点
const deleteNode = (nodeId) => {
    nodes.value = nodes.value.filter((node) => node.id !== nodeId);
    links.value = links.value.filter((link) => link.source !== nodeId && link.target !== nodeId);
};

// 保存流程图
const saveFlowchart = () => {
    // 打印图数据
    console.log('节点数据:', nodes.value);
    console.log('连线数据:', links.value);
    submit(); // 调用提交函数
};

// 提交
const submit = async () => {
    console.log('节点数据:', nodes.value);
    console.log('连线数据:', links.value);

    if (name == null || name == '') {
        ElMessage({
            message: '请先选择工艺流程',
            type: 'error',
        });
        return;
    }
    try {
        for (const node of nodes.value) {
            let superiorProcess = '0';
            let superiorProcessCode = '0';
            let lowerLevelProcess = '0';
            let lowerLevelProcessCode = '0';

            // 查找上级节点
            const incomingLink = links.value.find((link) => link.target === node.id);
            if (incomingLink) {
                const superiorNode = nodes.value.find((n) => n.id === incomingLink.source);
                if (superiorNode) {
                    superiorProcess = superiorNode.label;
                    superiorProcessCode = superiorNode.subLabel;
                }
            }

            // 查找下级节点
            const outgoingLink = links.value.find((link) => link.source === node.id);
            if (outgoingLink) {
                const lowerLevelNode = nodes.value.find((n) => n.id === outgoingLink.target);
                if (lowerLevelNode) {
                    lowerLevelProcess = lowerLevelNode.label;
                    lowerLevelProcessCode = lowerLevelNode.subLabel;
                }
            }

            const values = {
                completion_status: '1',
                current_process: node.label,
                current_process_code: node.subLabel,
                locking_state: false,
                lower_level_process: lowerLevelProcess,
                lower_level_process_code: lowerLevelProcessCode,
                superior_process: superiorProcess,
                superior_process_code: superiorProcessCode,
                technological_process_code: name,
            };

            await technologicalprocessApi.add(values);
        }
        ElMessage({
            message: '提交数据成功',
            type: 'success',
            onClose: () => {
                router.push({ path: '/technology/technologicalprocess' });
            },
        });
    } catch (error) {
        console.error('提交数据失败:', error);
    }
};

// 搜索框相关
const searchQuery = ref('');
const filteredProcessList = computed(() => {
    if (!searchQuery.value) {
        return processList;
    }
    return processList.filter((item) =>
        item.name.toLowerCase().includes(searchQuery.value.toLowerCase())
    );
});

// 折叠相关
const collapsed = ref(false);
const toggleCollapse = () => {
    collapsed.value = !collapsed.value;
};
</script>

<style scoped>
.flow-designer {
    display: flex;
    height: 100vh;
    background: #f5f7fa;
    align-items: stretch;
    overflow: hidden;
    position: relative;
}

/* 左侧面板固定悬浮 */
.fixed-panel {
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    min-width: 100px;
    background: #fff;
    border-right: 1px solid #ebedf0;
    display: flex;
    flex-direction: column;
    z-index: 1;
    transition: width 0.3s ease;
}

.resize-handle {
    position: absolute;
    top: 0;
    right: 0;
    width: 5px;
    height: 100%;
    cursor: col-resize;
}

.panel-header {
    height: 56px; /* 固定高度 */
    padding: 0 16px;
    flex-shrink: 0; /* 禁止收缩 */
    border-bottom: 1px solid #f0f0f0;
    background: #fafafa;
    display: flex;
    gap: 8px;
    align-items: center;
}

.search-input {
    flex: 1;
    padding: 8px 12px;
    border: 1px solid #d9d9d9;
    border-radius: 4px;
    transition: border-color 0.3s ease;
}

.search-input:focus {
    outline: none;
    border-color: #1890ff;
}

.collapse-button {
    background: transparent;
    border: none;
    cursor: pointer;
    font-size: 18px;
    color: #666;
    transition: color 0.3s ease;
}

.collapse-button:hover {
    color: #1890ff;
}

.process-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px 12px;
    transition: opacity 0.3s ease;
}

.process-item {
    display: flex;
    align-items: center;
    padding: 10px 16px;
    margin: 8px 0;
    border-radius: 6px;
    background: #fff;
    border: 1px solid #f0f0f0;
    transition: all 0.2s;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.02);
}

.process-item:hover {
    border-color: #1890ff;
    box-shadow: 0 2px 8px rgba(24, 144, 255, 0.15);
    transform: translateY(-1px);
}

.process-item:active {
    transform: scale(0.98);
    opacity: 0.9;
}

.process-icon {
    width: 20px;
    height: 20px;
    border-radius: 4px;
    margin-right: 12px;
    box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.1);
}

.process-code {
    font-size: 12px;
    color: #999;
    margin-left: auto;
    font-family: monospace;
}

/* 右侧画布满屏 */
.fullscreen-canvas {
    width: 100%;
    height: 100vh;
    position: relative;
    overflow: auto;
    padding: 0;
    display: flex;
}

/* SVG画布尺寸修正 */
.fullscreen-canvas svg {
    width: 100%;
    height: 100%;
    background: #fafafa;
    margin: 0;
}

/* 流程节点样式优化 */
g[transform] {
    transition: transform 0.15s ease-out;
}

g[transform] rect {
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.08));
    transition: filter 0.2s;
}

g[transform]:hover rect {
    filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.12));
}

g[transform] text {
    user-select: none;
    pointer-events: none;
}

/* 连接线优化 */
path[stroke='#666'] {
    stroke: #8c8c8c;
    stroke-width: 1.5;
}

path[stroke='#666']:hover {
    stroke: #1890ff;
    stroke-width: 2;
}

/* 锚点优化 */
.anchor {
    stroke-width: 0;
    transition: all 0.2s;
}

.anchor:hover {
    r: 5;
    stroke: #fff;
    stroke-width: 2;
    filter: drop-shadow(0 0 2px rgba(24, 144, 255, 0.5));
}

.anchor.output {
    fill: #52c41a;
}

.anchor.input {
    fill: #ff4d4f;
}

/* 箭头标记优化 */
#arrowhead polygon {
    fill: #8c8c8c;
}

/* 保存按钮样式 */
.save-button {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 2;
    padding: 10px 16px;
    background: #1890ff;
    color: #fff;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 8px;
    transition: background 0.3s ease;
}

.save-button:hover {
    background: #40a9ff;
}
</style>    